#include "Server.h"

Server::Server():canal(FuncionesComunes::GedIdCanalServidor().c_str()),sem(FuncionesComunes::ConvertirACharPointer(ARCHIVO_SEMAFORO), 1),
log(FuncionesComunes::GetNombreLog())
{
	fifos.clear();
//	Log logServer(FuncionesComunes::GetNombreLog("conversacion"));
//	log = logServer;
}

Server::~Server() {
}

void Server::ejecutar() {
	sem.wait();
	log.write("");
	log.write("");
	log.write("*************************************************************************************");
	log.write("");
	log.write("[Server:] Conectando Servidor");
	log.write("");
	sem.signal();

	do{
		iniciarConversacion(canal);
	} while(hayParticipantes());
	sem.eliminar();
	terminarConversacion(canal);
}

void Server::iniciarConversacion(Fifo &canal) {

	int bytesLeidos = 0;
	char stroperacion[100];

	bytesLeidos = canal.leer(stroperacion, 100);
	stroperacion[bytesLeidos] = '\0';

	switch (stroperacion[0]) {
	case '0':
		registrarParticipante(stroperacion);
		break;
	case '1':
		eliminarParticipante(stroperacion);
		break;
	default:
		enviarMensaje(stroperacion);
		break;
	}
}

/**
 * Hace un broadcast de mensajes a todos los participantes de la conversacion
 */
void Server::enviarMensaje(string id){

	string s = id.substr(0,id.find_last_of(FuncionesComunes::Separador));
	int idCanal =atoi(s.c_str());
	map<int, string[2]>::iterator ite = fifos.find(idCanal);
	string mensaje = "[" + ite->second[0]+" dice:] ";
	mensaje += id.substr(id.find_last_of(FuncionesComunes::Separador)+1,id.size() - s.size());
	sem.wait();
	log.write("[Server:] se recibe la respuesta [" + ite->second[0] + "] " + id );
	sem.signal();
	map<int,string[2]>::iterator it;
	it = fifos.begin();
	//Itero sobre los canales restantes para enviar el mensaje
	while(it != fifos.end()){
		if(it->first != idCanal){
			//Abro el canal de bajada para cada uno de los clientes
			sem.wait();
			log.write("[Server:] se envía la respuesta " + mensaje + " a " + it->second[1] );
			sem.signal();
			Fifo canalBajada( FuncionesComunes::ConvertirACharPointer(it->second[1]));
			canalBajada.escribir(FuncionesComunes::ConvertirACharPointer(mensaje), 100);
			canalBajada.cerrar();
		}
		it++;
	}
}

/**
 * Termina la conversacion, liberando recursos.
 */
void Server::terminarConversacion(Fifo &canal) {
	sem.wait();
	log.write("");
	log.write("[Server:] Desconectando Servidor");
	log.write("");
	log.write("*************************************************************************************");
	sem.signal();
	canal.cerrar();
}

/*
 * Registra un nuevo canal entre el cliente y el servidor
 */
void Server::registrarParticipante(string id) {
	const char* nombrecanal = id.substr( id.find_first_of(FuncionesComunes::Separador)+1, id.length()).c_str();
	string participante(nombrecanal);
	int idCanal =atoi(id.substr(1,id.find_first_of(FuncionesComunes::Separador)-1).c_str());
	string nickname = participante.substr( participante.find_last_of(FuncionesComunes::Separador)+1, participante.length());
	sem.wait();
	log.write("[Server:] Se registro el participante " + nickname + " con numero de pid: "+ FuncionesComunes::ConvertirAString(idCanal));
	sem.signal();
	string canales[2] = {nickname, participante + "down"};
	fifos.insert(pair<int, string[2]> (idCanal, canales));
}

/**
 * Elimina a un participante de la conversación.
 */
void Server::eliminarParticipante(string id) {
	int idCanal =atoi(id.substr(1,id.find_first_of(FuncionesComunes::Separador)-1).c_str());
	sem.wait();
	log.write("[Server:] Se elimino Participante " + FuncionesComunes::ConvertirAString(idCanal));
	sem.signal();
	fifos.erase(idCanal);
}

bool Server::hayParticipantes(){
	return (!fifos.empty());
}

void Server::activarModoDebug(bool activar){
	log.activeDebug(activar);
}
